home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / embedded / simulato / v2_3_mc6.tz / v2_3_mc6 / testfiles / sim35.asm < prev    next >
Assembly Source File  |  1994-05-02  |  72KB  |  1,226 lines

  1. ;  Class         CDA 3101, Fall '91
  2. ;  Assn          Assembler/Simulator for SIM 35 hypothetical computer
  3. ;  Progam Name   sim35.asm
  4. ;
  5. ;  Description:  This program uses the Pseudo Assembler from programing 
  6. ;                assignment #2 as a basis for a full fleged assembler for the
  7. ;                SIM 35 hypothetical microporcessor. It also simulates execution
  8. ;                of native SIM35 code on a M68000 microprocessor.  The Pseudo
  9. ;                Assembler took single lines of input in assembly and checked
  10. ;                their syntax and produced a valid label table.  The new
  11. ;                implementation of this program takes single lines of input and
  12. ;                outputs errors if any syntax errors are encountered, produces a
  13. ;                valid label table that includes the addresses which corespond to
  14. ;                each label, and outputs "half-assembled code" to an area of
  15. ;                memory in the reserved in the data block of the program.  This
  16. ;                1/2 code consists of instructions in the following format: 
  17. ;                        1st byte :opcode in hex
  18. ;                        2nd byte :register operand in hex (not ASCII), or 00
  19. ;                        3rd byte :register operand in hex (not ASCII), or...
  20. ;                        3rd, 4th, and subsequent bytes: label or address in ASCII
  21. ;                When the END directive is encountered, then the second pass 
  22. ;                begins if and only if no errors were encountered in the first 
  23. ;                pass.  The second pass assembles the half-assembled code and 
  24. ;                the valid label table's addresses into native sim35 code and
  25. ;                stores it at $3000+ which simulates the loading address $0 in 
  26. ;                the sim35 computer.  The last part of the program uses the 
  27. ;                68000's instruction set to simulate instructions from the sim35 
  28. ;                code.  Registers D0-D3 are used to represent the registers R0-
  29. ;                R3 in the sim35 computer.  Memory addresses $3000-$33FF 
  30. ;                simulate the sim35's 10 bit addressable space: $0-$3FF.  
  31.  
  32.                                   
  33.  
  34.  
  35.  
  36.  
  37. ****************************
  38. *                          *                               
  39. *        DATA BLOCK        *
  40. *                          *                               
  41. ****************************
  42.  
  43. ;
  44. ;------------------------------------------------------------------------------
  45. ;  The following two storage spaces are set asside for valid labels.  The first
  46. ;  (ValidLabels) holds all valid labels encountered during assembly.  This is the
  47. ;  list that is checked to see if a label is a duplicate.  The other list holds
  48. ;  all labels encountered as operands and these are checked individually against
  49. ;  the ValidLabels list after the END directive is encountered.  Those labels
  50. ;  appearing on this list that do not also appear on the ValidLabels list are
  51. ;  output as undefined label errors (see below in the data block).  Each of
  52. ;  these lists is delimited by null characters and terminated by a carriage
  53. ;  return (ASCII $D).
  54. ;
  55. ;                                
  56.                      org    $5000       
  57. ValidLabels          ds.b   $168        ;12 bytes x 30 lines=$168
  58. UndefLabels          ds.b   $21C        ;9 bytes x 60 operands=$21C
  59.  
  60. ;
  61. ;------------------------------------------------------------------------------
  62. ;  The following three constants are useful in dealing with strings.
  63. ;
  64. ;
  65. CR                   equ    $D          ;carriage return
  66. null                 equ    $0          ;null string
  67. space                equ    $20         ;space
  68. ;
  69. ;------------------------------------------------------------------------------
  70. ;  The following string constants are used in input and output formatting.  
  71. ;
  72. ;
  73.                      cnop   0,2         ;alligns on a word boundary
  74. Prompt               dc.b   'Enter sourcecode: ',0
  75.                      cnop   0,2         ;alligns on a word boundary
  76. Heading              dc.b   'Results',0
  77.                      cnop   0,2         ;alligns on a word boundary
  78. Line                 dc.b   '-------',0
  79.                      cnop   0,2         ;alligns on a word boundary
  80. LongLine             dc.b   '----------------------------------------------------------',0
  81. ;
  82. ;------------------------------------------------------------------------------
  83. ;  The next few data spaces are buffers for input and manipulation of input.
  84. ;
  85. ;
  86.                      cnop   0,2         ;alligns on a word boundary
  87. Input                ds.b   41          ;room for a line of input
  88.                      cnop   0,2         ;alligns on a word boundary
  89. Label                ds.b   41          ;space to store label portion of input
  90.                      cnop   0,2         ;alligns on a word boundary
  91. Opcode               ds.b   41          ;space to store opcode portion of input
  92.                      cnop   0,2         ;alligns on a word boundary
  93. Operands             ds.b   41          ;space to store operands from input
  94.                      cnop   0,2         ;alligns on a word boundary
  95. TempLabel            ds.b   41          ;place to store a label while checking it
  96.                      cnop   0,2         ;alligns on a word boundary
  97. Program              ds.b   $4CE        ;lots 'o' space for 1/2 assembled code
  98.                      cnop   0,2         ;alligns on a word boundary
  99. Object.Ptr           ds.l   1           ;ptr to final location of obj code
  100.                      cnop   0,2         ;alligns on a word boundary
  101. Prog.Ptr             ds.l   1           ;ptr to addr for next line of 1/2 code
  102. ;
  103. ;------------------------------------------------------------------------------
  104. ;  The following flags and indicators are basically paramters passed from the
  105. ;  main body of the progam to subroutines and returned with altered values. 
  106. ;  The boolean flags occupy a byte each and are set to either 1 or 0 (the
  107. ;  meanings of these settings are discussed as each flag is enoucountered in the
  108. ;  program).  
  109. ;
  110. ;
  111.                      cnop   0,2         ;alligns on a word boundary
  112. OperandType          ds.b   1           ;If set to 0=RR, 1=RM, 2= none
  113.                      cnop   0,2         ;alligns on a word boundary
  114. OpcodeVal            ds.b   1           ;place to store actual #val of Opcode
  115.                      cnop   0,2         ;alligns on a word boundary
  116. ValidFlag            ds.b   1           ;boolean flag to show if label is valid
  117.                      cnop   0,2         ;alligns on a word boundary
  118. DupFlag              ds.b   1           ;boolean flag showing label duplication
  119.                      cnop   0,2         ;alligns on a word boundary
  120. EndofProg            ds.b   1           ;boolean flag representing end directive
  121.                      cnop   0,2         ;alligns on a word boundary
  122. ErrorFlag            ds.b   1           ;boolean flag:0=do second pass,1=don't
  123.                      cnop   0,2         ;alligns on a word boundary
  124. NegFlag              ds.b   1           ;boolean flag:sign of ds or dc operand
  125. ;
  126. ;------------------------------------------------------------------------------
  127. ;  The next block of data contains strings used to alert user of errors in plain
  128. ;  english.  Each is terminated in a null so the given subroutines can detect the
  129. ;  end of each string.
  130. ;
  131. ;
  132.                      cnop   0,2
  133. InvalidLab           dc.b   'Invalid Label',0
  134.                      cnop   0,2         ;alligns on a word boundary
  135. Miss1Operand         dc.b   'First Operand Missing',0
  136.                      cnop   0,2         ;alligns on a word boundary
  137. Miss2Operand         dc.b   'Second Operand Missing',0
  138.                      cnop   0,2         ;alligns on a word boundary
  139. MissingOpcode        dc.b   'Missing Opcode',0
  140.                      cnop   0,2         ;alligns on a word boundary
  141. IllegalOperand       dc.b   'Illegal Operand',0
  142.                      cnop   0,2         ;alligns on a word boundary
  143. Inval1Oprnd          dc.b   'First Operand Invalid',0
  144.                      cnop   0,2         ;alligns on a word boundary
  145. Inval2Oprnd          dc.b   'Second Operand Invalid',0
  146.                      cnop   0,2         ;alligns on a word boundary
  147. InvalidOpcode        dc.b   'Invalid Opcode',0
  148.                      cnop   0,2         ;alligns on a word boundary
  149. DuplicateLab         dc.b   'Duplicate Label',0
  150.                      cnop   0,2         ;alligns on a word boundary
  151. CantAssem            dc.b   'Error(s) encountered-Cannot Assemble',0
  152.                      cnop   0,2         ;alligns on a word boundary
  153. SecondMess           dc.b   'Second pass now underway...',0
  154.                      cnop   0,2         ;alligns on a word boundary
  155. ProgRun              dc.b   'Program is now running...',0
  156. ;
  157. ;------------------------------------------------------------------------------
  158. ;  The undefined label error is a continuous string starting at UDLabelErr and 
  159. ;  continuing through UdLabelName.  UdLabelName's contents are filled before
  160. ;  string is written (UdLabelName's contents will be terminated with a null at
  161. ;  this time).  Thus the label's name is append to make a custom message.
  162. ;
  163. ;
  164.                      cnop   0,2         ;alligns on a word boundary
  165. UDLabelErr           dc.b   'Undefined Label:  '
  166. UdLabelName          ds.b   40
  167. ;
  168. ;------------------------------------------------------------------------------
  169. ;  The entries of the following opcode table have the following format:
  170. ;  mnemonic,$FE,opcode in hex, $FF.  Each entry is in upper case and the opcode of
  171. ;  each is used later in assembling the object code, except with the assembler 
  172. ;  directives END, DC, and DS, which have false opcodes used to inform the 
  173. ;  assembler to carry out a directive.
  174. ;
  175. ;
  176.               cnop    0,2                ;alligns on a word boundary
  177. OpTable       dc.b    'AR',$FE,0,$FF     ;Add register
  178.               dc.b    'SR',$FE,1,$FF     ;Subtract register
  179.               dc.b    'LR',$FE,2,$FF     ;Load register
  180.               dc.b    'NLR',$FE,3,$FF    ;Negate and Load register
  181.               dc.b    'MR',$FE,4,$FF     ;Multiply register
  182.               dc.b    'DR',$FE,5,$FF     ;Divide register
  183.               dc.b    'BC',$FE,6,$FF     ;Branch Conditionally
  184.               dc.b    'A',$FE,7,$FF      ;Add Memory
  185.               dc.b    'S',$FE,8,$FF      ;Subtract Memory
  186.               dc.b    'L',$FE,9,$FF      ;Load Memory
  187.               dc.b    'M',$FE,$A,$FF     ;Multiply Memory
  188.               dc.b    'D',$FE,$B,$FF     ;Divide Memory
  189.               dc.b    'ST',$FE,$C,$FF    ;Store Memory
  190.               dc.b    'EXT',$FE,$D,$FF   ;Exit
  191.               dc.b    'DPR',$FE,$E,$FF   ;Dump Registers
  192.               dc.b    'DPM',$FE,$F,$FF   ;Dump Memory
  193.               dc.b    'DC',$FE,$10,$FF   ;Define Constant
  194.               dc.b    'DS',$FE,$11,$FF   ;Define Storage
  195.               dc.b    'END',$FE,$12,$FF  ;End Assembly
  196.               dc.b    $D                 ;End of table marker (carriage return)
  197. ;
  198. ;------------------------------------------------------------------------------
  199. ;  The following storage spaces are used by the simulation portion of this 
  200. ;  program.
  201. ;  
  202. ;
  203.                      cnop   0,2         ;alligns on a word boundary
  204. DestReg              ds.b   1           ;Temp storage for destination register
  205.                      cnop   0,2         ;alligns on a word boundary
  206. CondCode             ds.b   1           ;Simulated condition code      
  207.  
  208.  
  209.  
  210. ************************************
  211. *                                  *                               
  212. *        PROGRAM SOURCECODE        *
  213. *                                  *                               
  214. ************************************
  215.  
  216.               
  217. ;
  218. ;------------------------------------------------------------------------------
  219. ;  The first segment reads a line of input.  The label heading 'ReadANewLine' is
  220. ;  invoked when a new line needs to be read.
  221. ;
  222. ;
  223.               org     $1000
  224.               jsr     ClearScreen
  225.               move.b  #$FF,ValidLabels  ;Valid Label list is empty
  226.               move.b  #CR,UndefLabels   ;Undefined Label list is empty
  227.               move.b  #0,ErrorFlag      ;no error encountered yet
  228.               move.l  #$0000,Object.Ptr ;objective code starts at address 0
  229.               move.l  #Program,Prog.Ptr ;set pointer to begining of source strg
  230.  
  231. ReadANewLine  move.l #Prompt,A0        ;Points to input prompt
  232.               jsr     WriteString       ;Places prompt on screen
  233.               movea.l #Input,A0         ;Place to store line of input
  234.               jsr     ReadString        ;Read in line of input from keyboard
  235.               jsr     WriteEOL          ;Produce a carriage return
  236.               movea.l #Heading,A0       ;pointer to heading
  237.               jsr     WriteString       ;Prints heading 
  238.               jsr     WriteEOL          ;produce a carriage return
  239.               movea.l #Line,A0          ;Pointer to a line
  240.               jsr     WriteString       ;Draws the line
  241.               jsr     WriteEOL          ;produce a carriage return
  242.               movea.l #Input,A4         ;Pointer (called Ptr from now on) to input
  243. ;
  244. ;------------------------------------------------------------------------------
  245. ;  For each new line the temporary storage place for each field is
  246. ;  set to empty (i.e. their first characters are end of field characters [nulls]
  247. ;
  248. ;                     
  249.               move.b  #null,Label        ;end of field marker
  250.               move.b  #null,Opcode       ;end of field marker
  251.               move.b  #null,Operands     ;end of field marker
  252.  
  253. ;
  254. ;------------------------------------------------------------------------------
  255. ;  The next segment of code invokes the Scan and SkipSpaces subroutines in order
  256. ;  to split the Input line into three distinct fields, Label, Opcode, and
  257. ;  Operands.
  258. ;
  259. ;
  260.               movea.l #Label,A5          ;Set ptr to Label temporary field
  261.               jsr     Scan              ;Fill Label field from Input
  262.               
  263.               movea.l #Opcode,A5         ;Set ptr to Opcode temporary field
  264.               jsr     SkipSpaces        ;Skip ahead to next characters in string
  265.               jsr     Scan              ;Fill Opcode field from Input
  266.                                               
  267.  
  268.               movea.l #Operands,A5       ;Set ptr to Operands temporary field
  269.               jsr     SkipSpaces        ;Skip ahead to next characters in string
  270.               jsr     Scan              ;File Operands field from Input 
  271. ;
  272. ;
  273. ;------------------------------------------------------------------------------
  274. ;  The Analyize segment calls three main subroutines, ExamineLabel, 
  275. ;  ExamineOpcode, and ExamineOperands.  These three subroutines determine
  276. ;  wheter the syntax of each statement is legal, wether symbols are valid or
  277. ;  duplicated, and if the number and type of operands is in agreement with the
  278. ;  opcode's specifications.  These subroutines also store valid labels in a
  279. ;  table, output valid mnemonic's opcodes, display error messages and store
  280. ;  valid symbol opcodes in a table for cross referencing with the valid labels
  281. ;  table at the end of assembly.
  282. ;
  283. ;
  284.  
  285. Analyze       subq    #4,A7            ;pop last jsr to scan from stack
  286.               move.b  #0,EndofProg     ;set flag to false (not end of program)
  287.  
  288.               jsr     ExamineLabel     ;examine syntax of Label temp. string
  289.  
  290.               jsr     ExamineOpcode    ;examine syntax of Opcode temp. string
  291.               cmpi.b  #1,(EndofProg)   ;was END directive encountered?
  292.               beq     EndProg          ;if so, branch ahead to end
  293.  
  294.               jsr     ExamineOperand   ;examine syntax of Operands temp. string
  295.  
  296.               jsr     WriteEOL         ;output a carriage return
  297.               movea.l #LongLine,A0     ;points to line which seperates input
  298.               jsr     WriteString      ;draws this dividing line
  299.               jsr     WriteEOL         ;another carriage return
  300.               bra     ReadANewLine     ;if not, get the next line and go again
  301. ;
  302. ;------------------------------------------------------------------------------
  303. ;  This section of the main program loads each label from the Undefined Labels
  304. ;  table (a table which holds all labels encountered in the Opcode field)
  305. ;  against every label in the Valid Labels table until it either finds a match
  306. ;  or finds that there is no duplicate label in the Valid Labels table.  If the
  307. ;  "Undefined" label turns out to have a counterpart on the Valid labels table,
  308. ;  then no action is taken.  If, however, the "undefined" label is truly
  309. ;  undefined, then the label's name (resident in TempLabel because that's where
  310. ;  it is put when it is checked against the valid list) is passed to the
  311. ;  UndefError subroutine that prints an error message that includes the
  312. ;  offending label's name.
  313. ;
  314. ;
  315. EndProg       movea.l #UndefLabels,A6  ;set ptr at begining of list
  316.  
  317. Loop          cmpi.b  #CR,(A6)         ;End of list?
  318.               beq     SecondPass       ;if so, start assembly
  319.               movea.l #TempLabel,A5    ;if not set ptr to begining of templabel
  320. 1$            move.b  (A6)+,(A5)+      ;copy a character from list to templabel
  321.               cmpi.b  #null,(A6)       ;end of this table entry?
  322.               bne     1$               ;if not keep copying until done w/it
  323.               clr.b   (A5)             ;if at end, place a null at end of temp
  324.               jsr     DupCheck         ;check if this undef appears on valid list
  325.               cmpi.b  #0,DupFlag       ;is it truly undefined?
  326.               beq     UndefError       ;If so tell the user
  327. MoveAhead     addq    #1,A6            ;Move ahead to next entry
  328.               bra     Loop             ;check next entry
  329. ;
  330. ;------------------------------------------------------------------------------
  331. ;  The following segment of code performs the final assembly of the half 
  332. ;  assembled code into native sim35 code.
  333. ;
  334. ;
  335. SecondPass      cmpi.b  #1,ErrorFlag     ;Error in first pass?
  336.                 beq     ToughLuck        ;If so end assembler/simulator
  337.                 jsr     ClearScreen      ;Clear the screen
  338.                 movea.l #SecondMess,A0   ;If not, tell user second pass is on
  339.                 jsr     WriteString      ;write this message
  340.                 jsr     WriteEOL         ;produce a carriage return
  341.                 movea.l #Program,A1      ;set ptr to begining of source
  342.                 movea.l #$3000,A2        ;set ptr to begining of obj code
  343.  
  344. NextInstruction clr.w   D0               ;clear space for first instruction
  345.                 move.b  (A1)+,D0         ;get an opcode
  346.                 cmpi.b  #$12,D0          ;end of assembly?
  347.                 beq     Simulate         ;if so, then execute SIM35 program
  348.                 clr.w   D5               ;clear register for object code
  349.                 cmpi.b  #5,D0            ;is opcode <=5? (an RR)
  350.                 bgt     1$               ;if not, check 2c if it is an RM
  351.                 muls    #16,D0           ;move opcode to second nibble
  352.                 add.b   D0,D5            ;put opcode in objective
  353.                 clr.w   D0               ;clear space for 1st operand
  354.                 move.b  (A1)+,D0         ;get first operand (hex num 0-3)
  355.                 muls    #4,D0            ;move 1st oprnd to bytes 3 and 2
  356.                 add.b   D0,D5            ;put first operand in objective
  357.                 clr.w   D0               ;clear space for second operand
  358.                 move.b  (A1)+,D0         ;get second operand (hex num 0-3)
  359.                 add.b   D0,D5            ;put second operand into objective
  360.                 move.b  D5,(A2)+         ;store objective in program
  361.                 bra     NextInstruction  ;assemble next instruction
  362.  
  363. 1$              cmpi.b  #$C,D0           ;is opcode <=$C? (an RM)
  364.                 bgt     NoOpernds        ;if not check 2c ifr it has no opernds
  365.                 muls    #$1000,D0        ;move opcode to 1st 4 bytes of word
  366.                 add.w   D0,D5            ;put opcode into objective
  367.                 clr.w   D0               ;clear space for 1st operand
  368.                 move.b  (A1)+,D0         ;get first operand
  369.                 muls    #$400,D0         ;place first operand after opcode
  370.                 add.w   D0,D5            ;put 1st operand in objective
  371.                 cmpi.b  #'9',(A1)        ;is first character >9?
  372.                 bgt     LabelAddr        ;if not it is a label address
  373.                 movea.l A1,A0            ;pass parametyer for ASCII to decimal
  374.                 jsr     ASCII2Dec        ;convert ASCII to decimal
  375.                 add.w   D0,D5            ;place second operand in objective
  376.                 move.b  D5,D6            ;store 1st half of objective temporarily
  377.                 lsr.w   #8,D5            ;get second half of objective
  378.                 move.b  D5,(A2)+         ;store 2nd half of objective in program
  379.                 move.b  D6,(A2)+         ;store 1st half of objective in program
  380.                 bra     NextInstruction  ;Assemble next instruction
  381.  
  382. LabelAddr       movea.l #TempLabel,A0    ;ptr for parameter passing
  383. CopyChar        move.b  (A1)+,(A0)+      ;copy from source to TempLabel
  384.                 cmpi.b  #null,(A1)       ;at end of Label?
  385.                 bne     CopyChar         ;if not copy next character
  386.                 move.b  #null,(A0)       ;put terminal char on templabel
  387.                 jsr     DupCheck         ;find match on label list
  388.                 add.w   D6,D5            ;d6 holds address:put on objective
  389.  
  390.                 move.b  D5,D6            ;store 1st half of objective temporarily
  391.                 lsr.w   #8,D5            ;get second half of objective
  392.                 move.b  D5,(A2)+         ;store 2nd half of objective in program
  393.                 move.b  D6,(A2)+         ;store 1st half of objective in program
  394.                 addq.w  #1,A1            ;account for null @ end of label
  395.                 bra     NextInstruction  ;Assemble next instruction
  396.  
  397. NoOpernds       cmpi.b  #$F,D0           ;is opcode >$F?
  398.                 bgt     DataDirective    ;if so it must be a DC or DS
  399.                 muls    #16,D0           ;if not, move opcode to mst sig nibble
  400.                 add.b   D0,D5            ;put opcode into objective
  401.                 move.b  D5,(A2)+         ;move objective code into program
  402.                 bra     NextInstruction  ;assemble next instruction
  403.  
  404. DataDirective   cmpi.b  #$10,D0          ;is this a DC?
  405.                 bne     ItsaDS           ;If not it is a DS
  406.                 move.b  (A1)+,(A2)+      ;if it is a DC, put const into program
  407.                 bra     NextInstruction  ;Assemble next instruction
  408. ItsaDS          clr.w   D0               ;clear space for # of bytes to skip
  409.                 move.b  (A1)+,D0         ;get high order of word
  410.                 lsl.w   #8,D0            ;move to high order position of word
  411.                 move.b  (A1)+,D1         ;get low order of word
  412.                 add.w   D1,D0            ;combine low and high order words
  413.                 add.w   D0,A2            ;leave those bytes blank
  414.                 bra     NextInstruction   ;assemble next instruction
  415. ;
  416. ;------------------------------------------------------------------------------
  417. ;  If an error occured in the first pass, then assembly cannot take place.  The 
  418. ;  second pass is skiped and the simulation is skipped.  The program jumps
  419. ;  straight to the end.  I call it tough luck because my assembler is soooo user
  420. ;  unfriendly that if you make one little error you must reenter the whole
  421. ;  program again (you can't even use the backspace key).  Tough Luck indeed!
  422. ;
  423. ;
  424. ToughLuck       movea.l #CantAssem,A0    ;ptr to tough luck message
  425.                 jsr     WriteString      ;display error
  426.                 jsr     WriteEOL         ;produce a carraige return
  427.                 bra     Finito           ;end the assembler/simuilator
  428.  
  429.  
  430. ;
  431. ;------------------------------------------------------------------------------
  432. ;  The Simiulate portion of this program reads native SIM35 code from memory 
  433. ;  starting at $3000, and extending to $33FF.  These addresses are used to
  434. ;  simulate the 10 bits of addressing space of the SIM35.  The DPR and DPM
  435. ;  instructions have not been implemented, they are treated as a NOP.  A byte in
  436. ;  main memory (within the data block) has been set aside for the simulated
  437. ;  condition code.  Often, the simulator will copy the m68000 condition code
  438. ;  into this memory location in order to keep the integrity of the sim35
  439. ;  condition code while the 68000 process other instructions.
  440. ;
  441. ;
  442. Simulate      movea.l #ProgRun,A0      ;set ptrto show message
  443.               jsr     WriteString      ;Display message
  444.               jsr     WriteEOL         ;produce a carriage return
  445.               movea.l #$3000,A0        ;set ptr to begining of simulated memory
  446. DoInst        clr.l   D4               ;clear the opcode register
  447.               clr.l   D5               ;clear a working register
  448.               move.b  (A0)+,D4         ;get an instruction
  449.               move.b  #16,D5           ;binary 10000
  450.               divs    D5,D4            ;opcode in LOword,operands in HOword
  451.               swap    D4               ;revers order in above comment
  452.               clr.l   D5               ;clear register for source operand
  453.               clr.l   D6               ;clear register for dest operand
  454.               move.b  D4,D5            ;put source and dest in dest register
  455.               swap    D4               ;Opcode in Low Order word
  456.               move.b  #4,D6            ;binary 100
  457.               divs    D6,D5            ;dest reg in LOword,source in HOword
  458.               move.b  D5,D6            ;dest reg in D6
  459.               swap    D5               ;source reg in D5
  460.               cmpi.b  #5,D4            ;is opcode >5?
  461.               bgt     MemInst          ;If so it may have an address operand
  462.               cmpi.b  #0,D5            ;Is source reg=0?
  463.               bne     1$               ;if not, it may be 1
  464.               move.b  D0,D5            ;if it is 0, put value in D5
  465.               bra     Arithmetic       ;execute instruction
  466. 1$            cmpi.b  #1,D5            ;Is source reg=1?
  467.               bne     2$               ;if not, it may be 2
  468.               move.b  D1,D5            ;if it is 1, put value in D5
  469.               bra     Arithmetic       ;execute instruction
  470. 2$            cmpi.b  #2,D5            ;Is source reg=2?
  471.               bne     3$               ;if not, it must be 3
  472.               move.b  D2,D5            ;if it is 2, put value in D5
  473.               bra     Arithmetic       ;execute instruction
  474. 3$            move.b  D3,D5            ;put value in D5
  475.               bra     Arithmetic
  476.  
  477. MemInst       cmpi.b  #$D,D4           ;Is this a no operand instruction?
  478.               bge     ExitOrNot        ;if so, check 2c if it is an EXT
  479.               clr.l   D7               ;clear space for memory address
  480.               move.b  (A0)+,D7         ;get next byte (last 8 bits of address)
  481.               muls    #256,D5          ;move 1st two bits to bits 9 and 8
  482.               add.w   D5,D7            ;put bits 9 and 8 with 7-0
  483.               add.w   #$3000,D7        ;convert to simulated address
  484.               movea.l D7,A1            ;prepare to get value from memory
  485.               cmpi.b  #$C,D4           ;is this a store memory?
  486.               beq     MemoryStg        ;If so, deal with it elsewhere
  487.               cmpi.b  #6,D4            ;is it a branch instruction?
  488.               beq     BranchIns        ;If so, deal with it elsewhere
  489.               move.b  (A1),D5          ;store value from memory in source
  490.               subi.b  #7,D4            ;make opcode equivalent to RR version
  491.               cmpi.b  #2,D4            ;is it a multiply or divide?
  492.               bgt     1$               ;if so, move opcode foreward 1 (skip NLR)
  493.               bra     Arithmetic       ;if not, execute the instruction
  494. 1$            addq.b  #1,D4            ;move opcode foreward 1
  495.               bra     Arithmetic       ;execute instruction
  496.  
  497. ExitOrNot     cmpi.b  #$D,D4           ;is it an EXT instruction?
  498.               bne     DoInst           ;If not, process next instruciton
  499.               bra     Finito           ;If so, end program
  500.  
  501. Arithmetic    move.b  D6,DestReg       ;make a copy of the destination register
  502.               cmpi.b  #0,D6            ;is the destination register =0?
  503.               bne     1$               ;if not keep checking
  504.               move.b  D0,D6            ;if so store value in D6
  505.               bra     DoMath           ;Add,sub,Div,Mult,etc
  506. 1$            cmpi.b  #1,D6            ;is the destination register =1?
  507.               bne     2$               ;if not keep checking
  508.               move.b  D1,D6            ;if so store value in D6
  509.               bra     DoMath           ;Add,sub,Div,Mult,etc
  510. 2$            cmpi.b  #2,D6            ;is the destination register =2?
  511.               bne     3$               ;if not it must be 3
  512.               move.b  D2,D6            ;if so store value in D6
  513.               bra     DoMath           ;Add,sub,Div,Mult,etc
  514. 3$            move.b  D3,D6            ;store value in D6
  515.  
  516. DoMath        ext.w  D5                ;sign extend the source
  517.               ext.l  D5                ;sign extend the source
  518.               ext.w  D6                ;sign extend the destination
  519.               ext.l  D6                ;sign extend the destination
  520.               cmpi.b  #0,D4            ;is it an add?
  521.               bne     1$               ;if not check 2c if it is a sub
  522.               add.b   D5,D6            ;add source to destination
  523.               bra     UpdateCC         ;Update the simulated CC
  524. 1$            cmpi.b  #1,D4            ;is it a subtract?
  525.               bne     2$               ;if not, check 2c if it is a LR
  526.               sub.b   D5,D6            ;subtract source from destination
  527.               bra     UpdateCC         ;Update the simulated CC
  528. 2$            cmpi.b  #2,D4            ;is it a LR?
  529.               bne     3$               ;if not, check 2c if it is a NLR
  530.               move.b  D5,D6            ;move source into destination
  531.               bra     UpdateCC         ;Update the simulated CC
  532. 3$            cmpi.b  #3,D4            ;is it a NLR?
  533.               bne     4$               ;if not, check 2c if it is a multiply   
  534.               neg.b   D5               ;negate source
  535.               move.b  D5,D6            ;move source into destination
  536.               bra     UpdateCC         ;Update the simulated CC
  537. 4$            cmpi.b  #4,D4            ;is it a multiply?
  538.               bne     5$               ;if not it must be a divide
  539.               muls    D5,D6            ;multiply destination by source
  540.               bra     UpdateCC         ;Update the simulated CC
  541. 5$            divs    D5,D6            ;divide the destination by the source
  542.  
  543. UpdateCC      move.w  sr,(CondCode)    ;move condition code into simulated CC
  544.  
  545. StoreResult   move.b  (DestReg),D5     ;get orriginal destination register
  546.               cmpi.b  #0,D5            ;Is dest reg=0?
  547.               bne     1$               ;if not, it may be 1
  548.               move.b  D6,D0            ;if it is 0, put value in D0 (R0)
  549.               bra     DoInst           ;Process next instruction
  550. 1$            cmpi.b  #1,D5            ;Is dest reg=1?
  551.               bne     2$               ;if not, it may be 2
  552.               move.b  D6,D1            ;if it is 1, put value in D1 (R1)
  553.               bra     DoInst           ;Process next instruction
  554. 2$            cmpi.b  #2,D5            ;Is dest reg=2?
  555.               bne     3$               ;if not, it must be 3
  556.               move.b  D6,D2            ;if it is 2, put value in D2 (R2)
  557.               bra     DoInst           ;Process next instruction
  558. 3$            move.b  D6,D3            ;put value in D3 (R3)
  559.               bra     DoInst           ;Process next instruction
  560.  
  561. MemoryStg     cmpi.b  #0,D6            ;is the source register =0?
  562.               bne     1$               ;if not keep checking
  563.               move.b  D0,D6            ;if so store value in D6
  564.               bra     StoreIt          ;Store the value
  565. 1$            cmpi.b  #1,D6            ;is the source register =1?
  566.               bne     2$               ;if not keep checking
  567.               move.b  D1,D6            ;if so store value in D6
  568.               bra     StoreIt          ;Store the value in memory
  569. 2$            cmpi.b  #2,D6            ;is the source register =2?
  570.               bne     3$               ;if not it must be 3
  571.               move.b  D2,D6            ;if so store value in D6
  572.               bra     StoreIt          ;Store the value in memory
  573. 3$            move.b  D3,D6            ;store the value in memory
  574.  
  575. StoreIt       move.b  D6,(A1)          ;store value in memory
  576.               move    sr,CondCode      ;store CC in simulated CC
  577.               bra     DoInst           ;Process next instruction
  578.  
  579. BranchIns     cmpi.b  #0,D6            ;Is it a BRA?
  580.               bne     BEQ              ;if not it may be a BEQ
  581.               bra     TakeBranch       ;if so, then take the branch
  582.  
  583. BEQ           cmpi.b  #1,D6            ;is it a BEQ?
  584.               bne     BGT              ;if not it may be a BGT
  585.               btst    #2,(CondCode+1)  ;test zero bit
  586.               bne     TakeBranch       ;if it is set, then take the branch
  587.               bra     DoInst           ;otherwise, process next instruction
  588.  
  589. BGT           cmpi.b  #2,D6            ;is it a BGT?
  590.               bne     BLT              ;if not it must be a BLT
  591.               btst    #2,(CondCode+1)  ;test the zero bit
  592.               bne     DoInst           ;if it is set, don't branch
  593.               btst    #3,(CondCode+1)  ;test the N bit
  594.               beq     TakeBranch       ;If both N&V are reset take the branch
  595.               bra     DoInst           ;if they differ, process next instruction
  596.                                        
  597. BLT           btst    #3,(CondCode+1)  ;test the N bit
  598.               bne     TakeBranch       ;if both V&N nare set, take the branch
  599.               bra     DoInst           ;if they are same, don't branch
  600.  
  601. TakeBranch    movea.l A1,A0            ;set simulated PC to reflect branch
  602.               bra     DoInst           ;implement instruction at new location
  603.  
  604.  
  605. ;
  606. ;------------------------------------------------------------------------------
  607. ;  This is a standard exit
  608. ;
  609. ;
  610. Finito        move    #228,D7
  611.               trap    #14
  612.  
  613.  
  614. *****************************
  615. *                           *                               
  616. *        SUBROUTINES        *
  617. *                           *                               
  618. *****************************
  619.  
  620. ;
  621. ;------------------------------------------------------------------------------
  622. ;  The Scan subroutine moves through the Input line and copies it into the
  623. ;  stretch of memory that is pointed to by A5 (the temporary pointer).  It
  624. ;  continues to copy characters until it hits a space (end of field, so time to
  625. ;  change where temporary pointer points to) or a carriage reutrn (end of input
  626. ;  so stop scanning altogether by BRANCHING back to continuation point).  Since
  627. ;  this subroutine eventually branches back (rather than returns) a pop of the
  628. ;  stack is the first action taken when the branch is taken (to the Analyze
  629. ;  block).
  630. ;
  631. ;
  632. Scan          move.w  #39,D0           ;Maximum no. of characters per field
  633. 1$            cmpi.b  #null,(A4)       ;Is the Input ptr at the end?
  634.               beq     Analyze          ;If so BRANCH back (popped later)
  635.               cmpi.b  #space,(A4)      ;If not, check if ptr is at end of field
  636.               beq     Return           ;If it is, Scan routin complete
  637.               move.b  (A4)+,(A5)+      ;If not, copy a character into temporary
  638.               move.b  #null,(A5)       ;Put end of field marker (eof) behind it
  639.               dbra    D0,1$            ;branch to move next (unless > 40 chars)
  640. Return        rts                      ;normal return from subroutine
  641. ;
  642. ;------------------------------------------------------------------------------
  643. ;  The SkipSpaces routine simply skips over intervening spaces between fields.
  644. ;  If it encounters an end of line it cannot differentiate between it and
  645. ;  another character, and since the ptr is left pointing to the first available
  646. ;  character, the Scan routine will pick up this case.
  647. ;
  648. ;
  649. SkipSpaces    cmpi.b  #space,(A4)+      ;check to see if we're at a space & incr
  650.               beq     SkipSpaces       ;if so move ahead
  651.               subq    #1,A4
  652.               rts                      ;if not, our ptr points to next character
  653.  
  654. ;
  655. ;------------------------------------------------------------------------------
  656. ;  The ExamineLabel routine calls LabelCheck and Dupcheck to determine if a
  657. ;  label is first valid and second duplicated.  If the label fails either test
  658. ;  (boolean flags are returned from the two subroutines to indicate the success
  659. ;  or failure of a particular label) then the appropriate error message is given.
  660. ;  In particular, when the label is found to be invalid, a short routine that
  661. ;  is called InvalidLabel handels the issuance of Invalid Label errors.  If
  662. ;  the label passes these tests, however, ExamineLabel jumps to a branch of
  663. ;  itself called ItsOK.  ItsOK puts the new, valid label into the ValidLabels
  664. ;  list.  The first part of ItsOK traverses this list to the first empty spot.  
  665. ;  The next section (labeled PutInList) actually places the label name along
  666. ;  with the address that the label corresponds to into the
  667. ;  next available slot in the list.  The last section, called FullNulls pads the
  668. ;  Label name with nulls so that it takes up 12 bytes exactly.  This code
  669. ;  segment also replaces the end of list marker (cariage return) after this
  670. ;  newest addition to the list.
  671. ;
  672. ;
  673. ExamineLabel  movea.l #Label,A4        ;points to beginning of Label field
  674.               cmpi.b  #null,(A4)       ;Is there a label?
  675.               beq     ExitRoutine      ;If not, exit this routine
  676.  
  677.               cmpi.b  #'$',(A4)+       ;is first char a "$"?
  678.               bne     InvalidLabel     ;if not, label is invalid
  679.  
  680.               movea.l #TempLabel,A5    ;set ptr to begining of temp label
  681. 1$            cmpi.b  #0,(A4)          ;at end of label field?
  682.               beq     2$               ;if so, finish templabel and continue
  683.               move.b  (A4)+,(A5)+      ;move character in TempLabel
  684.               bra     1$               ;see if whole label copied, again if not
  685. 2$            move.b  #0,(A5)          ;put terminal null into TempLabel 
  686.  
  687.               jsr     LabelCheck       ;checks to see if it is valid
  688.               cmpi.b  #0,ValidFlag     ;is flag set to valid (true=0)
  689.               bne     InvalidLabel     ;if not, label is invalid
  690.               jsr     DupCheck         ;checks to see if label is a duplicate
  691.               cmpi.b  #0,DupFlag       ;is flag set to non-duplicate (0=false)
  692.               beq     ItsOK            ;if so, label is ok to add to table
  693.  
  694.               movea.l #DuplicateLab,A0 ;if not, move ptr to begining of err msg
  695.               jsr     WriteString      ;write error message
  696.               jsr     WriteEOL         ;produce a carriage return
  697.               rts                      ;return to Analayze for Opcode analasys
  698.  
  699. ItsOK         movea.l #ValidLabels,A4  ;move ptr to begining of list
  700. 1$            cmpi.b  #$FF,(A4)+       ;at end of list yet?
  701.               bne     1$               ;if not keep moving until at E.O.L.
  702.               subq    #1,A4            ;if we are move ptr onto E.O.L. marker
  703.               movea.l #TempLabel,A5    ;set ptr to begining of label to add
  704.               move.w  (Object.Ptr),(A4)+ ;1st 2 bytes of entry show address
  705.               move    #9,D0            ;counter for 10 characters to be read
  706.  
  707. PutInList     move.b  (A5)+,(A4)+      ;copy a character from templabel to list
  708.               subq    #1,D0            ;take away one for each character in lbl
  709.               cmpi.b  #null,(A5)       ;at end of label?
  710.               bne     PutInList        ;if not keep copying characters
  711.  
  712. FillNulls     move.b  #null,(A4)+      ;put a null at end of label
  713.               dbra    D0,FillNulls     ;add nulls 'till 10 chars entered tot.
  714.               move.b  #$FF,(A4)        ;put E.O.L. marker in list
  715.  
  716. ExitRoutine   rts                      ;go back to Analyze (to look at Opcodes)
  717. ;
  718. ;------------------------------------------------------------------------------
  719. ;  The invalid label routine displays the invalid label error message and
  720. ;  returns control to the main program (the Analyze block).
  721. ;
  722. ;
  723. InvalidLabel  movea.l #InvalidLab,A0   ;tell user that his label...
  724.               jsr     WriteString      ;                      ...is invalid
  725.               jsr     WriteEOL         ;produce a carriage return
  726.               move.b  #1,ErrorFlag     ;set flag to show that error ocurred
  727.               rts                      ;Go back to Analyze                     
  728. ;
  729. ;------------------------------------------------------------------------------
  730. ;  The LabelCheck routine recives a string whose first character is stored in
  731. ;  TempLabel and who is expected to be a valid label.  If this is called from
  732. ;  examen label, the calling routine already checked to see that a dollar sign
  733. ;  ($) preceded this string.  If the calling routine was ExamineOpcodes, such a
  734. ;  check was not necessary.  In all cases, valid labels start with a letter, so
  735. ;  this routine first makes sure that the first character is a letter (upper
  736. ;  case).  Beyond that, this routine makes sure that there are no more than nine
  737. ;  characters, that the label is terminated by a colon (:) followed by a #null,
  738. ;  and that the the intermittent characters are alphanumeric.  If the label
  739. ;  passes all of these tests, then its flag is left with a value of 0 (=valid 
  740. ;  label).  If not, the flag is set to 1 (invalid label).  The calling
  741. ;  subroutine uses the status of the flag to decide what course of action to
  742. ;  take.
  743. ;
  744. ;                          
  745. LabelCheck    move.b  #0,ValidFlag     ;set boolean flag to say label is valid
  746.               movea.l #TempLabel,A5    ;set pointer to temporary string holder
  747.               cmpi.b  #'A',(A5)        ;check to see if character < 'A'
  748.               blt     Invalid          ;if so it is invalid
  749.               cmpi.b  #'Z',(A5)+       ;check to see if character > 'Z'
  750.               bgt     Invalid          ;if so it is invalid
  751.  
  752. Check         move    #5,D0            ;# of iterations (1st char+ 6 chars + ":")
  753. Again         cmpi.b  #null,(A5)       ;Is character a null?
  754.               beq     Invalid          ;If so, then lable is invalid
  755.               cmpi.b  #':',(A5)        ;at end of label?
  756.               beq     EndOfLabel       ;if so make a final check
  757.               cmpi.b  #'Z',(A5)        ;>'Z'?
  758.               bgt     Invalid          ;if so it is invalid
  759.               cmpi.b  #'0',(A5)        ;<'0'?
  760.               blt     Invalid          ;if so it is invalid
  761.               cmpi.b  #'9',(A5)        ;compare to "9"
  762.               ble     NextChar         ;if <="9" then it is ok, check next
  763.               cmpi.b  #'A',(A5)        ;compare to "A"
  764.               bge     NextChar         ;if >="A" then it is a letter, OK so far
  765.               bra     Invalid          ;if no checks passed, it is invalid
  766.  
  767. NextChar      addq    #1,A5            ;increment ptr to next character
  768.               dbra    D0,Again         ;decrement count and read next character
  769.               cmpi.b  #':',(A5)        ;is 9th character a colon?
  770.               bne     Invalid          ;if not it is invalid
  771.  
  772. EndOfLabel    addq    #1,A5            ;look at next character
  773.               cmpi.b  #0,(A5)          ;is this the last character?
  774.               bne     Invalid          ;if not, then the label is invalid
  775.               rts                      ;alls well, return to ExamenLabel
  776.  
  777. Invalid       move.b #1,ValidFlag      ;set ValidFlag to false (invalid=1)
  778.               rts                      ;return to ExamenLabel
  779. ;
  780. ;------------------------------------------------------------------------------
  781. ;  The DupCheck routine compares the string with starting address tempstring
  782. ;  to all the strings recorded in the ValidLabels Table.  If it finds a match
  783. ;  it sets the flag (DupFlag) to 1, otherwise it sets it to 0.  The usefulness
  784. ;  of this information is dependant upon the calling subroutine.  If LabelCheck
  785. ;  calls it, a duplicate result (DupFlag=1) causes an error (duplicate label
  786. ;  error) to occur.  If ExamineOpcodes was the calling routine, then a no
  787. ;  duplicate result (DupFlag=0) would produce an error (undefined label error)
  788. ;  In the second pass, DupCheck is used to match opcodes to their 
  789. ;  location numbers so the first 2 bytes of each label are stored in 
  790. ;  a data register (D6) as each label is checked.
  791. ;
  792. ;
  793. DupCheck      move.b  #0,DupFlag       ;Not a duplicate yet
  794.               movea.l #TempLabel,A5    ;set ptr to begining of label to check
  795.               movea.l #ValidLabels,A4  ;set ptr to begining of Valid Label list
  796.               cmpi.b  #$FF,(A4)         ;is list empty?
  797.               beq     Done             ;cannot be a duplicate if list is empty
  798.  
  799. CheckALabel   move.w  (A4)+,D6         ;save address for use by 2nd pass
  800.               move.w  #9,D0            ;counter to see how far to skip to next
  801. CheckChar     subq.b  #1,D0            ;one less character to skip to next lbl
  802.               cmpm.b  (A4)+,(A5)+      ;are they duplicate characters?
  803.               bne     NextLabel        ;If they aren't equal, check against next
  804.               cmpi.b  #null,(A4)       ;Is this the end of the label?
  805.               beq     ItsADup          ;If so, then we have a duplication
  806.               bra     CheckChar        ;If not, check next character
  807.  
  808. NextLabel     addq.w  #1,A4            ;move forward 1 character
  809.               dbra    D0,NextLabel     ;move ahead till this entry is passed
  810.               cmpi.b  #$FF,(A4)        ;is this the end of the list?
  811.               bne     LookAgain        ;if not set ptr in TempLabel to begining
  812. Done          rts                      ;if so, label is not a duplication
  813.  
  814. LookAgain     movea.l #TempLabel,A5    ;set ptr in TempLabel to begining
  815.               bra     CheckALabel      ;start checking the next label
  816.  
  817. ItsADup       move.b  #1,DupFlag       ;set flag to show it is a duplicate
  818.               rts                      ;return to calling subroutine
  819.  
  820.  
  821. ;
  822. ;------------------------------------------------------------------------------
  823. ;  The ExamineOpcode subroutine first checks to see if the Opcode field is
  824. ;  empty.  If it is then it displays a missing opcode error and returns to the
  825. ;  Analyze block.  Otherwise, it checks the characters in the Opcode Files
  826. ;  versus the characters of the first Opcode in the table.  If this does not
  827. ;  form a match all the way up to null in the opcode field and "1" in the table
  828. ;  ("1" is the separatetor between the menomnic and the opcode in the table),
  829. ;  then it resets the pointer to the begining of the Opcode field and moves the
  830. ;  table pointer ahead until it is at the begining of the next mnemonic.  If
  831. ;  this goes on all the way through the entire table without an exact match,
  832. ;  then the user is furnished with an invalid opcode error.  If however the 
  833. ;  mnemonic turns out to be valid, then two things happen. First, the ptr in the 
  834. ;  object code is incremented the appropriate ammount (1 or 2 bytes except in the 
  835. ;  case of DS and DC).  Second, the propoer opcode (a word length hex integer) is 
  836. ;  placed into memory (starting at Program for the first command).  In either
  837. ;  case (valid or invalid) a value must be chosen for the OperandType [0=RR,
  838. ;  1=RM, 2=none].  Since the operand arrived at by this subroutine is in ASCII
  839. ;  form, inequalities that test which group a particualr opcode falls into must
  840. ;  use the ASCII values of the opcodes.  Between the ASCII value for 0 and the
  841. ;  ASCII value for 5 the OperandType is RR  (0).  Above 5 but below D (it does
  842. ;  not matter that there are intervening characters between the numbers and the
  843. ;  letters in ASCII, the operand can never be one of these intervening characters
  844. ;  so we can act as if they were not there) the OperandType is RM (1).  At D and
  845. ;  above there are no operands (type2).  This information is stored in
  846. ;  OperandType (location in memory) for the next major subroutine
  847. ;  (ExamineOperands) to access.  Opcodes $10 and $11 (DC and DS) also use 
  848. ;  OperandType 2 which causes the ExamineOperands routine to ignore their 
  849. ;  operands.  The operand of these instructions is handled in a special 
  850. ;  subroutine.    
  851. ;
  852. ;
  853. ExamineOpcode movea.l #Opcode,A4       ;ptr to begining of Opcode field
  854.               cmpi.b  #0,(A4)          ;Is this field empty?
  855.               beq     MisNOp           ;If so we are mising an Operand
  856.  
  857.               movea.l #OpTable,A5      ;ptr to opcode table
  858. CheckOp       movea.l #Opcode,A4       ;ptr to begining of Opcode field
  859. CheckOpChar   cmpm.b  (A4)+,(A5)+      ;do we have a match?
  860.               bne     NextOpcode       ;if not, see what is the next on table
  861.               cmpi.b  #$FE,(A5)        ;at the dividing character?
  862.               bne     CheckOpChar      ;if not check the next character
  863.               cmpi.b  #0,(A4)          ;if so are we out of characters in temp?
  864.               bne     NextOpcode       ;if not, see what is next on the table
  865.               addq    #1,A5            ;if we have a match, then skip to opcode
  866.               move.b  (A5),OpcodeVal   ;Put opcode for mnemonic in OpcodeVal
  867.               bra     ValidOp          ;it is valid:add to object.ptr and source
  868.  
  869. NextOpcode    cmpi.b  #$FF,(A5)+       ;if not, then see if we're at next opcode
  870.               bne     NextOpcode       ;if not move until we are there
  871.               cmpi.b  #CR,(A5)         ;at end of table?
  872.               beq     InvalidOp        ;if so, mnemonic in temp is invlaid
  873.               bra     CheckOp          ;if not we're at next opcode, check it.
  874.  
  875. ValidOp       cmpi.b  #$12,OpcodeVal   ;Did we just have an END directive?
  876.               beq     EndDirective     ;If so then deal with it accordingly
  877.               cmpi.b  #$5,OpcodeVal    ;Is opcode>5
  878.               bgt     Type1or2         ;If so, set Operand value accordingly
  879.               move.b  #0,OperandType   ;If not it is RR type,
  880.               bra     OpcodeStuff      ;Increment ptr and do 1/2 assembly
  881. Type1or2      cmpi.b  #$C,OpcodeVal    ;Is opcode >$C?
  882.               bgt     Type2            ;if so, set Operand value accordingly
  883.               move.b  #1,OperandType   ;if not it is type 1
  884.               bra     OpcodeStuff      ;Increment ptr and do 1/2 assembly
  885. Type2         move.b  #2,OperandType   ;it must be opearand type 2
  886.  
  887. OpcodeStuff   cmpi.b  #$10,OpcodeVal   ;Is opcode a DC or DS?
  888.               bge     DfnDirective     ;If so, deal with it in a subroutine
  889.               movea.l (Prog.Ptr),A0    ;1/2 ptr=location of next intruction
  890.               move.b  (OpcodeVal),(A0)+ ;Store opcode in 1/2 assm format
  891.               move.l  A0,Prog.Ptr      ;Increment 1/2 assm ptr
  892.               cmpi.b  #1,OperandType   ;Is this Operand Type RM?
  893.               bne     RR               ;If not, 1 byte displacement is needed
  894.               addq.w  #1,(Object.Ptr)  ;If so add an extra byte displacement
  895. RR            addq.w  #1,(Object.Ptr)  ;move ahead 1 byte in object code
  896.               rts                      ;return to analyze
  897.  
  898. MisNOp        movea.l #MissingOpcode,A0 ;set ptr to error message
  899.               jsr     WriteString      ;display error message
  900.               jsr     WriteEOL         ;produce a carriage return
  901.               move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  902.               rts                      ;Return to Analyze
  903.  
  904. InvalidOp     movea.l #InvalidOpcode,A0 ;ptr to error string
  905.               jsr     WriteString      ;show user his error
  906.               jsr     WriteEOL         ;produce a carriage return
  907.               move.b  #0,OperandType   ;assumption:invalid opcodes are RR
  908.               move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  909.               rts                      ;return to analyze
  910.  
  911. EndDirective  movea.l (Prog.Ptr),A0     ;set ptr to next available space in source
  912.               move.b  #$12,(A0)        ;put end directive in source (1/2 assm)
  913.               move.b  #1,EndofProg     ;set program ending flag
  914.               rts                      ;return to analyze
  915.  
  916. DfnDirective  move.b #0,NegFlag        ;set sign of operand to positive (for now)
  917.               movea.l #Operands,A0     ;move ptr to begining of operand field
  918.               cmpi.b  #'-',(A0)        ;is this a negative number?
  919.               bne     1$               ;if not, do not set negation flag
  920.               move.b  #1,NegFlag       ;number is negative
  921.               addq.l  #1,A0            ;point to first digit, past '-' character
  922. 1$            jsr     ASCII2Dec        ;convert to ASCII into a hex number
  923.               cmpi.b  #1,ValidFlag     ;Check 2c if operand was invalid
  924.               beq     Inv              ;if so, deliver error message
  925.               cmpi.b  #1,NegFlag       ;is this a negative number?
  926.               bne     ProcessDir       ;if not go ahead &see if it is DS or DC
  927.               neg.w   D0               ;if it is negative, negate value first
  928.  
  929. ProcessDir    movea.l (Prog.Ptr),A0     ;set ptr to source (1/2 assembled)
  930.               move.b  (OpcodeVal),(A0)+ ;store opcode in source
  931.  
  932.               cmpi.b  #$10,OpcodeVal   ;is this a DC?
  933.               bne     Storage          ;if not it is a DS
  934.  
  935.               move.b  D0,(A0)+         ;store operand in source
  936.               move.l  A0,Prog.Ptr      ;store incremented pointer
  937.               addq.w  #1,Object.Ptr    ;make space for a 1 byte constant
  938.               rts                      ;return to Analyze
  939.  
  940. Storage       move.w  D0,D1            ;copy the operand
  941.               lsr      #8,D1           ;get first byte of operand
  942.               move.b  D1,(A0)+         ;store first byte of operand in source
  943.               move.b  D0,(A0)+         ;store second byte of operand in source
  944.               move.l  A0,Prog.Ptr      ;store incremented pointer
  945.               tst.w   D0               ;Is the opcode negative?
  946.               blt     Inv              ;If so it is invalid
  947.               add.w   D0,Object.Ptr    ;if not, move ahead # of bytes=to operand
  948.               rts                      ;return to Analyze
  949.  
  950. Inv           movea.l #Inval1Oprnd,A0  ;ptr to error message
  951.               jsr     WriteString      ;display error message
  952.               jsr     WriteEOL         ;produce a carriage return
  953.               move.b  #1,ErrorFlag     ;set flag to show that na error occured
  954.               rts                      ;return to Analyze
  955. ;
  956. ;------------------------------------------------------------------------------
  957. ;  The ExamineOperand Subroutine checks both the first and second operands of an
  958. ;  instruction.  Since there are three possibilities for the correct configuration
  959. ;  of operands (depending upon which opcode was entered), this routine first
  960. ;  checks to see if we need no operands at all (type 2)  If we do not need them,
  961. ;  then we go back to the main program (Analyze) without checking any further.
  962. ;  If it is either type RR or RM (0 and 1 respectively), then we check to make
  963. ;  sure the operand field is not empty.  If it is missing operand errors are
  964. ;  displayed.  Once we know there is something in the field, we check the first
  965. ;  operand. If it is not and integer between 0 and 3 inclusive and error will
  966. ;  be printed (either invalid operand error or missing operand error). 
  967. ;  Regardless of the validity of the first operand, the second operand's validity
  968. ;  is tested.  If the type is RR, then the second operand must be and integer
  969. ;  between 0 and 3 (the test for this is identical to the test used for the first
  970. ;  operand, but the code is repeated-like a macro would produce).  If the second
  971. ;  operand is not 0-3, then either an invalid second operand error will occur,
  972. ;  or a missing operand error will occur, whichever is appropriate.  If the type
  973. ;  is RM, then the operand can be either a number from 0 to 1023 or a valid 
  974. ;  label (sans the $).  If this type of label is expected, the first character is
  975. ;  tested.  If it is >=0 and <=9 it is assumed that it is going to be an integer.
  976. ;  The length of the integer is tested.  If it only has three characters, then it
  977. ;  is valid as long as the other two characters are digits.  If it has four
  978. ;  characters, then the fist must be a 1 for validity.  The second must be a 0. 
  979. ;  These comparisons are dirrect, if either one fails, the address is thrown out
  980. ;  as invalid.  The thrid character must be either a 0, 1, or 2.  If it is a 0 or
  981. ;  1, then the last character is checked to see if it is a digit, if so, the
  982. ;  address is valid.  If the third character is a 2, then the last character 
  983. ;  must be a digit between 0 and 3 inclusive.  If this is so, then the operand is
  984. ;  valid.  If not an invalid operand error is displayed.  If, however, the first 
  985. ;  character of the second operand is not a digit, then it is checked to see if
  986. ;  it is a label (in MayBeLabel branch).  The previously defined LabelCheck
  987. ;  routine determines the validity of the label, and the boolean flag it returns
  988. ;  is used determine this routine's course of action.  If the label is not valid
  989. ;  (ValidFlag = 1), then an invalid label error is produced.  If the label is
  990. ;  valid, then it is added to the end of the Undefined Labels list.  This list
  991. ;  does not actually represent Undefined Labels, but it instead represents all
  992. ;  the labels that could be undefined.  This is the set of all labels encountered
  993. ;  as an operand.  At the end of the program, these "Undefined Labels" are
  994. ;  checked against the valid label list to see if there are any that really are
  995. ;  undefined.  UndefError handles this process and is described in the following
  996. ;  section.  If the operands are valid, then the number 0-3 is stored in the 
  997. ;  source (1/2 assembled code) and memory locations and labels are stored as
  998. ;  strings.
  999. ;
  1000. ;
  1001. ExamineOperand  cmpi.b  #2,OperandType   ;Is this an opcode w/o operands?
  1002.                 bne     CheckOperands    ;If not we have to check the operands
  1003.                 rts                      ;if it is we go no problems, return
  1004.  
  1005. CheckOperands   movea.l #Operands,A4     ;move ptr to begining of operands field
  1006.                 cmpi.b  #null,(A4)       ;is field empty?
  1007.                 bne     CheckFirst       ;I hope not, we need two operands
  1008.  
  1009.                 movea.l #Miss1Operand,A0 ;If so, get set for first error.
  1010.                 jsr     WriteString      ;Print first error
  1011.                 jsr     WriteEOL         ;produce a carriage return
  1012.                 move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  1013.  
  1014. MissSecond      movea.l #Miss2Operand,A0 ;Get set for missing second operand err
  1015.                 jsr     WriteString      ;Print second error
  1016.                 jsr     WriteEOL         ;produce a carriage return
  1017.                 move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  1018.                 rts                      ;that's it, we've got error(s) in ops
  1019.  
  1020. CheckFirst      cmpi.b  #',',(A4)        ;if first operand missing?
  1021.                 bne     2$               ;if not then proceed
  1022.                 movea.l #Miss1Operand,A0 ;but if it is, relinquish error mssg.
  1023.                 jsr     WriteString      ;print error message
  1024.                 jsr     WriteEOL         ;produce a carriage return
  1025.                 move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  1026.                 bra     CheckSecond      ;look at second operand
  1027. 2$              cmpi.b  #'0',(A4)        ;is first char <'0'?'
  1028.                 blt     3$               ;If so first operand is illegal
  1029.                 cmpi.b  #'3',(A4)+       ;is first character >'3'?
  1030.                 bgt     3$               ;If so first operand is illegal
  1031.                 cmpi.b  #null,(A4)       ;is that all?
  1032.                 beq     MissSecond       ;if so, second is missing
  1033.                 cmpi.b  #',',(A4)        ;are we at the 2nd operand yet?
  1034.                 beq     StoreFirst       ;if so check it for validity
  1035. 3$              movea.l #Inval1Oprnd,A0  ;if not at end of first yet,1st invald
  1036.                 jsr     WriteString      ;print error message
  1037.                 jsr     WriteEOL         ;produce a carriage return
  1038.                 move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  1039. 4$              cmpi.b  #',',(A4)        ;at comma yet?
  1040.                 beq     StoreFirst       ;if so, 1st is OK-check second
  1041.                 cmpi.b  #0,(A4)+         ;Is that all (nhothing after comma)
  1042.                 beq     MissSecond       ;If so we are missing second operand
  1043.                 bra     4$               ;otherwise, keep looking for comma
  1044.  
  1045. StoreFirst      subq.l  #1,A4            ;point to byte showing 1st oprnd reg
  1046.                 move.b  (A4)+,D0         ;copy ASCII into a temporary register
  1047.                 subi.b  #$30,D0          ;convert from ASCII to decimal
  1048.                 movea.l (Prog.Ptr),A0    ;get address of ptr in 1/2 assmbly
  1049.                 move.b  D0,(A0)+         ;copy hex operand in source (1/2 asm)
  1050.                 move.l  A0,Prog.Ptr      ;increment pointer to next byte
  1051.  
  1052. CheckSecond     addq    #1,A4            ;move to 1st char of 2nd op
  1053.                 movea.l #TempLabel,A5    ;set ptr in TempLabel
  1054.                 cmpi.b  #0,(A4)          ;is there a second operand?
  1055.                 bne     1$               ;if there is go ahead and examine it
  1056.                 bra     MissSecond       ;If not, then display error
  1057. 1$              move.b  (A4)+,(A5)+      ;Copy a character into TempLabel
  1058.                 cmpi.b  #0,(A4)          ;is that all?
  1059.                 bne     1$               ;if not, continue to copy
  1060.                 move.b  (A4),(A5)        ;if so put a null at end of TempLabel
  1061.                 movea.l #TempLabel,A5    ;reset pointer
  1062.                 cmpi.b  #1,OperandType   ;Is second opperand a memory address?
  1063.                 beq     MemAddr          ;If so then deal with it as such
  1064.                 cmpi.b  #'0',(A5)        ;if not, it first character a '0'?
  1065.                 blt     Invalid2nd       ;if it is <'0', then it is invalid
  1066.                 cmpi.b  #'3',(A5)+       ;is 1st char >'3'?
  1067.                 bgt     Invalid2nd       ;if so, it is invalid
  1068.                 cmpi.b  #0,(A5)          ;Are there any other characters?
  1069.                 bne     Invalid2nd       ;If there are, then 2nd operand invalid
  1070.                 subq.l  #1,A5            ;point to byte showing 1st oprnd reg
  1071.                 move.b  (A5)+,D0         ;copy ASCII into a temporary register
  1072.                 subi.b  #$30,D0          ;convert from ASCII to decimal
  1073.                 movea.l (Prog.Ptr),A0    ;get address of ptr in 1/2 assmbly
  1074.                 move.b  D0,(A0)+         ;copy hex operand in source (1/2 asm)
  1075.                 move.l  A0,Prog.Ptr      ;increment pointer to next byte
  1076.                 rts                      ;otherwise, 2nd is OK-return to Analyze
  1077.  
  1078. Invalid2nd      movea.l #Inval2Oprnd,A0  ;set ptr to error message
  1079.                 jsr     WriteString      ;Display error message
  1080.                 jsr     WriteEOL         ;produce a carriage return
  1081.                 move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  1082.                 rts                      ;return to Analyze
  1083.  
  1084. MemAddr         cmpi.b  #'0',(A5)        ;Is first char <'0'?
  1085.                 blt     MaybeLabel       ;It doesn't start w/a# it maybealable
  1086.                 cmpi.b  #'9',(A5)        ;Is first char >'9'?
  1087.                 bgt     MaybeLabel       ;Dosen't start w/a#, May be a Label
  1088.                 move    #4,D0            ;Character counter
  1089. 1$              cmpi.b  #0,(A5)+         ;at end of label?
  1090.                 dbeq    D0,1$            ;if not,check next(but exit if>4chars)
  1091.                 move    #4,d1            ;this value used to calculate # of chars
  1092.                 sub     D0,D1            ;now D1 holds actual number of chars
  1093.                 movea.l #TempLabel,A5    ;Set ptr to begining
  1094.                 cmpi.b  #3,D1            ;is # of chars<=3?
  1095.                 bgt     FourChars        ;Then It must have four chars
  1096.  
  1097. ThreeOrLess     addq.l  #1,A5            ;Skip first char "x", we know 0 <= x <= 9
  1098. TestADigit      cmpi.b  #null,(A5)       ;at the end?
  1099.                 beq     ExitOK           ;if so, operand is good
  1100.                 cmpi.b  #'0',(A5)        ;Is character <'0'?
  1101.                 blt     Invalid2nd       ;If so operand is invalid
  1102.                 cmpi.b  #'9',(A5)+       ;is character >'9'?
  1103.                 bgt     Invalid2nd       ;If so operand is invalid              
  1104.                 bra     TestADigit       ;if it was ok, test next digit
  1105.  
  1106. FourChars       cmpi.b  #4,D1            ;Are ther four characters?
  1107.                 bne     Invalid2nd       ;If not then it is invalid
  1108.                 cmpi.b  #0,(A5)          ;Is 1st char a zero?
  1109.                 beq     ThreeOrLess      ;If so check as a three character #
  1110.                 cmpi.b  #'1',(A5)+       ;Is 1st char a '1'?
  1111.                 bne     Invalid2nd       ;If not it cannot be valid
  1112.                 cmpi.b  #'0',(A5)+       ;Is 2nd char a '0'?
  1113.                 bne     Invalid2nd       ;If not, it cannot be valid
  1114.                 cmpi.b  #'0',(A5)        ;Is third char <'0'?
  1115.                 blt     Invalid2nd       ;If so label is invalid
  1116.                 cmpi.b  #'2',(A5)+       ;Is third char a 1 or 0?
  1117.                 blt     1$               ;If so check fourth character
  1118.                 bne     Invalid2nd       ;If 3rd is not otherwise a 2 is invalid
  1119.                 cmpi.b  #'0',(A5)        ;If 4th <'0'?
  1120.                 blt     Invalid2nd       ;If so then invalid
  1121.                 cmpi.b  #'3',(A5)        ;Is 4th >'3'?
  1122.                 bgt     Invalid2nd       ;If so then invalid
  1123.                 bra     ExitOK           ;otherwise, its valid
  1124.  
  1125. 1$              cmpi.b  #'0',(A5)        ;is 4th char<'0'?
  1126.                 blt     Invalid2nd       ;If so then invalid
  1127.                 cmpi.b  #'9',(A5)        ;is 4th char>'9'?
  1128.                 bgt     Invalid2nd       ;If so then it is invalid
  1129.                 bra     ExitOK           ;otherwise, its valid
  1130.  
  1131. MaybeLabel      jsr     LabelCheck       ;use subroutine to check validity
  1132.                 cmpi.b  #0,ValidFlag     ;Is label valid?
  1133.                 bne     Invalid2nd       ;If not it is invalid
  1134.                 movea.l #TempLabel,A5    ;set ptr back to begining
  1135.                 movea.l #UndefLabels,A4  ;set ptr to begining of undefined table
  1136. 1$              cmpi.b  #CR,(A4)+        ;at end of undef label list?
  1137.                 bne     1$               ;loop until end is reached
  1138.                 subq    #1,A4            ;move pointer last step to very end
  1139. 2$              move.b  (A5)+,(A4)+      ;copy a character
  1140.                 cmpi.b  #0,(A5)          ;End of label?
  1141.                 bne     2$               ;loop until end of label is reached
  1142.                 move.b  (A5),(A4)+       ;place null on undefined label list
  1143.                 move.b  #CR,(A4)         ;place and end of list mark on undef list
  1144.  
  1145. ExitOK          movea.l #TempLabel,A5    ;set ptr to begining of label
  1146.                 movea.l (Prog.Ptr),A0    ;set ptr to next space in source
  1147. 1$              move.b  (A5)+,(A0)+      ;copy a character into source
  1148.                 cmpi.b  #null,(A5)       ;at end of label?
  1149.                 bne     1$               ;if not keep copying till done
  1150.                 move.b  #null,(A0)+      ;if so, put end of label mark in source                      
  1151.                 move.l  A0,(Prog.Ptr)    ;record updated ptr position
  1152.                 rts                      ;label is ok, return to Analyze
  1153.  
  1154. ;                                                                              
  1155. ;------------------------------------------------------------------------------
  1156. ;  The ASCII2Dec routine converts an ASCII string of digits that represent a 
  1157. ;  decimal number into their corresponding hex value.  It recives a pointer to
  1158. ;  the string in A0, and places the final hex number in D0.
  1159. ;
  1160. ;
  1161. ASCII2Dec       move.b  #0,ValidFlag     ;Operand is not invalid yet
  1162.                 clr.w   D0               ;This will hold the number
  1163.                 clr.w   D1               ;set digit counter to 0
  1164.  
  1165. DigitCount      cmpi.b  #0,(A0)+         ;at end of operand?
  1166.                 beq     BackToBeg        ;if so, move ptr to begining of operand
  1167.                 addq.w  #1,D1            ;if not, then increment digit counter
  1168.                 bra     DigitCount       ;and look for next digit
  1169.  
  1170. BackToBeg       addq.b  #1,D1            ;adjust for last postincrements
  1171.                 add.w   D1,A1            ;move ahead in obj code during 2nd pass
  1172.                 suba.w  D1,A0            ;move ptr back to begining of operand
  1173.                 subq.b  #1,D1            ;set digit count back to correct #
  1174. NextDigit       cmpi.b  #'0',(A0)        ;is next digit <0?
  1175.                 blt     Inval            ;if so, it is invalid
  1176.                 cmpi.b  #'9',(A0)        ;is next digit >9?
  1177.                 bgt     Inval            ;If so, it is invalid
  1178.                 clr.w   D2               ;clear space for hex digit
  1179.                 move.b  (A0),D2          ;put ASCII into a register
  1180.                 subi.b  #$30,D2          ;convert to a decimal digit
  1181.                 cmpi.w  #1,D1            ;is this the last digit (digit ctr=1)?
  1182.                 beq     LastDigit        ;if so, add final digit & exit routine
  1183.                 move.w  D1,D3            ;if not, prepare an exponent of 10
  1184.                 move.w  #1,D4            ;initalize multiplier
  1185.                 subq.w  #2,D3            ;account for first multiple
  1186.  
  1187. Multiple        muls    #10,D4           ;increase by a power of ten
  1188.                 dbra    D3,Multiple      ;reduce exponent by one until done
  1189.  
  1190.                 muls    D4,D2            ;multiply digit by its place value
  1191.                 add.w   D2,D0            ;add this number to total
  1192.                 addq.l  #1,A0            ;move to next digit
  1193.                 subq.w  #1,D1            ;reduce power
  1194.                 bra     NextDigit        ;process next digit
  1195.  
  1196. LastDigit       add.w   D2,D0            ;add final digit (times 1)
  1197.                 rts                      ;end routine
  1198.  
  1199. Inval           move.b  #1,ValidFlag     ;Set flag to show that label is invalid
  1200.                 rts                      ;end routine
  1201.  
  1202. ;                                                                              
  1203. ;------------------------------------------------------------------------------
  1204. ;  The UndefError routine moves the label's name (held in memory starting at 
  1205. ;  TempLabel) to memory starting at UdLabelName.  This memory location is
  1206. ;  dirrectly after the string which makes up the undefined error message.  So
  1207. ;  this routine embeds the name of the undefined label into the error message,
  1208. ;  and then prints the message.
  1209. ;
  1210. ;        
  1211. UndefError    movea.l #TempLabel,A5    ;set ptr to begining of undefined label
  1212.               movea.l #UdLabelName,A3  ;set ptr to "fill in the blank" in messg.
  1213. 2$            move.b  (A5)+,(A3)+      ;copy a character
  1214.               cmpi.b  #null,(A5)       ;end of undefined label?
  1215.               bne     2$               ;if not continue copying until done
  1216.               clr.b   (A3)             ;set end of label mark in message
  1217.               movea.l #UDLabelErr,A0   ;set pointer to label error
  1218.               jsr     WriteString      ;write error message
  1219.               jsr     WriteEOL         ;produce a carriage return
  1220.               move.b  #1,ErrorFlag     ;Set flag to show that an error occured
  1221.               bra     MoveAhead        ;go back to main program to check next  
  1222.  
  1223.               Include "C:\Routines"  ;Routines for line input and output
  1224.  
  1225.               END
  1226.